#include "libcomm.h"

static MessageParser::ParseResult ParseStreamMessage(Buffer& buffer, Buffer& message, unsigned short checkcode, int nHitMaxMsgSize)
{
	unsigned short nCheckCode = 0;
	int nMsgSize = 0;

	// check message checkcode
	//
	if(buffer.size() < StreamMessageParser::CheckCodeSize)
	{
		// message checkcode not enough. 
		return MessageParser::PR_NEEDMORE;
	}
	memcpy(&nCheckCode,buffer.get(),StreamMessageParser::CheckCodeSize);
	if(nCheckCode != checkcode)
	{
		LOGWARN("message CHECK-CODE(0x%x) is not correct.",nCheckCode);
		return MessageParser::PR_ERROR;
	}

	// check message size.
	//
	if(buffer.size() < StreamMessageParser::HeaderSize + StreamMessageParser::CheckCodeSize)
	{
		// message header not enough. 
		return MessageParser::PR_NEEDMORE;
	}
	memcpy(&nMsgSize,buffer.get() + StreamMessageParser::CheckCodeSize,StreamMessageParser::HeaderSize);
	if(nMsgSize < 0 || nMsgSize > nHitMaxMsgSize)
	{
		LOGWARN("message HEADER-SIZE(%d) is not correct.",nMsgSize);
		return MessageParser::PR_ERROR;
	}

	// check message body.
	//
	if(buffer.size() - StreamMessageParser::HeaderSize - StreamMessageParser::CheckCodeSize < (size_t)nMsgSize)
	{
		// message body not enough.
		return MessageParser::PR_NEEDMORE;
	}
	message.resize(nMsgSize);
	memcpy(message.get(),buffer.get() + StreamMessageParser::HeaderSize + StreamMessageParser::CheckCodeSize,nMsgSize);

	buffer.consume(StreamMessageParser::HeaderSize + StreamMessageParser::CheckCodeSize + nMsgSize);
	return MessageParser::PR_SUCESS;
}

// **** NOT-MTSafe ****
MessageParser::ParseResult StreamMessageParser::Parse(Buffer& message, unsigned int timeoutMs)
{
	while(true)
	{
		ParseResult result = ParseStreamMessage(m_tmpBuffer,message,m_checkcode,m_nHitMaxMsgSize);
		if(PR_NEEDMORE != result)
			return result;

		ScopedPtr<Buffer> buffer(this->Pop(timeoutMs));
		if(buffer == NULL)
			return PR_NEEDMORE;

		MYLIB_ASSERT(buffer->size()>0);
		m_tmpBuffer.append(buffer->get(),buffer->size());
		continue;
	}

	// not execute here.
	return PR_ERROR;
}

void StreamMessageParser::PackageMessage(Buffer& message, const void* buffer, int size)
{
	MYLIB_ASSERT(size <= m_nHitMaxMsgSize && size > 0);
	message.resize(size + StreamMessageParser::HeaderSize + StreamMessageParser::CheckCodeSize);
	memcpy(message.get(), &m_checkcode, StreamMessageParser::CheckCodeSize);									// CheckCode
	memcpy(message.get() + StreamMessageParser::CheckCodeSize, &size, StreamMessageParser::HeaderSize);			// HeaderSize
	memcpy(message.get() + StreamMessageParser::CheckCodeSize + StreamMessageParser::HeaderSize, buffer, size); // Buffer
}

//////////////////////////////////////////////////////////////////////////

static MessageParser::ParseResult ParseLineMessage(Buffer& buffer, Buffer& message, int nHitMaxMsgSize,const char* separator)
{
	int nSizeLine = strlen(separator);
	size_t i = 0;
	for (;i<buffer.size();i++)
	{
		if(buffer[i] == separator[0])
		{
			bool matched = true;
			for (int j=0;j<nSizeLine;j++)
			{
				if(i + j >= buffer.size() || buffer[i + j] != separator[j])
				{
					matched = false;
					break;
				}
			}
			if(matched)
				break;
		}
	}

	if(i == buffer.size())
	{
		// not found "\r\n".
		if(i > (size_t)nHitMaxMsgSize)
		{
			LOGWARN("message is too long.");
			return MessageParser::PR_ERROR;
		}
		return MessageParser::PR_NEEDMORE;
	}

	buffer[i] = 0;
	message.resize(i+1);
	memcpy(message.get(), buffer.get(), i+1);// add '\0'
	buffer.consume(i+nSizeLine);// consume "\r\n"
	return MessageParser::PR_SUCESS;
}

// **** NOT-MTSafe ****
MessageParser::ParseResult LineMessageParser::Parse(Buffer& message, unsigned int timeoutMs)
{
	while(true)
	{
		ParseResult result = ParseLineMessage(m_tmpBuffer,message,m_nHitMaxMsgSize,m_separator);
		if(PR_NEEDMORE != result)
			return result;

		ScopedPtr<Buffer> buffer(this->Pop(timeoutMs));
		if(buffer == NULL)
			return PR_NEEDMORE;

		MYLIB_ASSERT(buffer->size()>0);
		m_tmpBuffer.append(buffer->get(),buffer->size());
		continue;
	}
	
	// not execute here.
	return PR_ERROR;
}

void LineMessageParser::PackageMessage(Buffer& message, const void* buffer, int size)
{
	MYLIB_ASSERT(size <= m_nHitMaxMsgSize && size > 0);
	int nSizeLine = strlen(m_separator);
	message.resize(size + nSizeLine);
	memcpy(message.get(), buffer, size);
	memcpy(message.get() + size, m_separator, nSizeLine);
}